#include "Vitality.h"
#include "../GameObjects/Character.h"
#include "../CommandManager.h"
#include "../StringHelper.h"

#include <algorithm>

Vitality::Vitality()
	: Component("Vitality"), alive(true), blood_bank(100)
{
	//add(CommandManager::getSingleton()->getCommand("wield"));
	
}

Vitality::~Vitality()
{
}

void Vitality::update(unsigned int tick)
{
	int bleed_amount = 0;
	std::for_each(begin(bodyparts), end(bodyparts), [&](const BodyPart &bodypart)
	{
		bleed_amount += bodypart.bleed(tick);
	});
	blood_bank -= bleed_amount;

	std::for_each(begin(bodyparts), end(bodyparts), [&](BodyPart &bodypart)
	{
		bodypart.heal(tick);
	});
}

void Vitality::addBodypart(Character::BodyPart part, int hp, unsigned int bleed_rate, unsigned int hp_reproduction_rate)
{
	bodyparts.push_back(Vitality::BodyPart(part, hp, bleed_rate, hp_reproduction_rate));
}

unsigned int Vitality::getHP(Character::BodyPart bodypart) const
{
	for(unsigned int i = 0; i < bodyparts.size(); i++)
	{
		if(bodyparts[i].part == bodypart)
			return bodyparts[i].hp;
	}
	return 0;
}

void Vitality::setHP(Character::BodyPart bodypart, unsigned int hp)
{
	for(unsigned int i = 0; i < bodyparts.size(); i++)
	{
		if(bodyparts[i].part == bodypart)
		{
			bodyparts[i].hp = (int)hp;
			return;
		}
	}
}

void Vitality::damage(const CharacterPtr &character, Character::BodyPart bodypart, unsigned int dmg, const RoomPtr &room)
{
	unsigned int i = 0;
	for(; i < bodyparts.size(); i++)
	{
		if(bodyparts[i].part == bodypart)
		{
			bodyparts[i].hp -= (int)dmg;
			break;
		}
	}

	if(blood_bank <= 0)
	{
		alive = false;
		std::for_each(begin(dieCallbacks), end(dieCallbacks), [&](const std::function<void(CharacterPtr, const RoomPtr &)> &callback)
		{
			callback(character, room);
		});
	}
	else
	{
		std::for_each(begin(dmgCallbacks), end(dmgCallbacks), [&](const std::function<void(const CharacterPtr &, Character::BodyPart bodypart, unsigned int)> &callback)
		{
			callback(character, bodypart, dmg);
		});
	}
}

void Vitality::heal(const CharacterPtr &character, unsigned int hp)
{
	std::for_each(begin(bodyparts), end(bodyparts), [&](BodyPart &bodypart)
	{
		bodypart.hp += (int)hp;
	});
	std::for_each(begin(healCallbacks), end(healCallbacks), [&](const std::function<void(const CharacterPtr &, unsigned int)> &callback)
	{
		callback(character, hp);
	});
}

std::string Vitality::getHealthReport(const Character * /*character*/, bool detailed) const
{
	std::string health_report = "";
	if(detailed)
	{
		std::for_each(begin(bodyparts), end(bodyparts), [&](const BodyPart &bodypart)
		{
			std::string bodypart_report = Character::getBodypartName(bodypart.part);
			if(bodypart.hp > 90)
				bodypart_report += " is perfectly healthy.";
			else if(bodypart.hp > 60)
				bodypart_report += " is bruised.";
			else if(bodypart.hp > 30)
				bodypart_report += " bleeds.";
			else if(bodypart.hp > 10)
				bodypart_report += " bleeds greviously!";
			else if(bodypart.hp >= 0)
				bodypart_report += " is oblitterated.";
			health_report += bodypart_report + "\n";
		});
	}
	else
	{
		if(blood_bank > 90)
			health_report = ""; //Report nothing
		else if(blood_bank > 60)
		{
			health_report += " has a few bruises.";
		}
		else if(blood_bank > 30)
		{
			health_report += " looks hurt";
		}
		else if(blood_bank > 10)
		{
			health_report += " looks really hurt";
		}
		else if(blood_bank > 0)
		{
			health_report += " is dying";
		}
	}
	return health_report;
}

void Vitality::registerDamageCallback(std::function<void(const CharacterPtr &, Character::BodyPart, unsigned int)> &&callback)
{
	dmgCallbacks.push_back(callback);
}

void Vitality::registerHealCallback(std::function<void(const CharacterPtr &, unsigned int)> &&callback)
{
	healCallbacks.push_back(callback);
}

void Vitality::registerDieCallback(std::function<void(CharacterPtr, const RoomPtr &)> &&callback)
{
	dieCallbacks.push_back(callback);
}
